package kiwi.assist.dev.guieditor.command {
	import avmplus.getQualifiedClassName;

	import fl.core.UIComponent;

	import ghostcat.util.ReflectUtil;

	import kiwi.assist.dev.guieditor.event.GUIEditorEvent;
	import kiwi.assist.dev.guieditor.model.ContainerConfig;
	import kiwi.assist.dev.guieditor.model.PropertyConfig;
	import kiwi.assist.dev.guieditor.model.StyleConfig;
	import kiwi.assist.dev.guieditor.model.UiConfig;
	import kiwi.assist.dev.guieditor.model.UiDetailVO;
	import kiwi.assist.dev.guieditor.model.format.BooleanFormat;
	import kiwi.assist.dev.guieditor.model.format.FilterFormat;
	import kiwi.assist.dev.guieditor.model.format.NumericFormat;
	import kiwi.assist.dev.guieditor.model.format.SkinFormat;
	import kiwi.assist.dev.guieditor.model.format.StringFormat;
	import kiwi.assist.dev.guieditor.model.format.StyleFormat;
	import kiwi.assist.dev.guieditor.model.format.TFFormat;
	import kiwi.assist.dev.util.SkinComponentAdapter;
	import kiwi.constproxy.ConstTextFormat;
	import kiwi.debug.Log;
	import kiwi.util.ArrayUtils;
	import kiwi.util.ObjectPool;
	import kiwi.util.bitmap.BitmapPool;
	import kiwi.util.sprintf;

	import org.robotlegs.mvcs.Command;

	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;

	/**
	 * 发布为as代码
	 * @author zhangming.luo
	 */
	public class PublishAsCommand extends Command {
		[Inject]
		public var detail : UiDetailVO;
		[Inject]
		public var event : GUIEditorEvent;
		/**
		 * 有皮肤
		 */
		private var useDisplayObject : Boolean;
		/**
		 * 有样式
		 */
		private var useSkin : Boolean;
		/**
		 * 有用到特殊值
		 */
		private var useValue : Boolean;
		/**
		 * 计数器(用来顶替noname时的名字序号)
		 */
		private var implCnt : int = 0;
		/**
		 * 最终的代码
		 */
		private var code : String;
		/**
		 * Meta的代码
		 */
		private var metaCode : String;
		/**
		 * 导入的代码
		 */
		private var importCode : String;
		/**
		 * 所有的声明代码
		 */
		private var declareCode : String;
		/**
		 * 背景部分
		 */
		private var backgroundCode : String;
		/**
		 * 构造的代码
		 */
		private var bodyCode : String;
		/**
		 * 基类的订制代码
		 */
		private var basebodyCode : String;
		/**
		 * 导入的队列
		 */
		private var importList : Array = [];
		/**
		 * meta队列
		 */
		private var metaList : Array = [];
		/**
		 * 导出完毕是否提示
		 */
		private var noAlert : Boolean;
		/**
		 * 基本的模板
		 */
		private var template : String =/**
		 * 代码的模板采用多行字符串来表达
		 */ 
		<![CDATA[package ${packageName}{
    ${import}
	/**
	 * 当ui需要被显示的时候触发
	 * 由添加到stage的代码触发
	 */
	[Event(name="active",type="flash.events.Event")]
	/**
	 * 初始化时触发的(一个实例只会触发一次)
	 * 由构建改ui的代码触发
	 */
	[Event(name="init",type="flash.events.Event")]
	public class ${className} extends ${baseContainer}{
		/**
		 * 默认的样式
		 */
		public static function getStyleDefinition() : Object {
			return ${baseContainer}.getStyleDefinition();
		}
 		/**
		 * 所有的子控件
		 */
		private var children : Array=[];
 
		/**
		 * 声明所有的控件
		 */
		${declare}
		
		public function ${className}(){
			super();
			// 设置基类的样式与属性
			${basebody}
		}
		
		/**
		 * 构造所有的控件并做基本的布局
		 */
		override protected function configUI() : void{
			super.configUI();
			${background}
			${body}
		}
		
		/**
		 * 更新一下
		 */
		override protected function draw():void{
			super.draw();
			updateView();
		}
		
		/**
		 * 更新孩子的drawNow
		 */
		final protected function updateView():void{
			for each(var child:UIComponent in children){
				child.drawNow();
			}
		}
	}
}]]>;
		private var useBgClass : Boolean;

		override public function execute() : void {
			super.execute();
			noAlert = event.data;
			prepare();
			if (detail.container) {
				generateBaseBody();
			} else {
				basebodyCode = "";
			}
			generateBg();
			generateBody();
			mergeImport();
			mergeMeta();
			merge();
			saveCode();
		}

		private function mergeMeta() : void {
			var codeList : Array = [];
			for each (var info:Object in metaList) {
				switch(info.type) {
					case "background":
						codeList.push(sprintf("[Background(type=\"%s\")]", getQualifiedClassName(info.clz)));
				}
			}
			codeList = ArrayUtils.createUniqueCopy(codeList);
			codeList.sort();
			metaCode = codeList.join("\n");
		}

		private function mergeImport() : void {
			useSkin && (declareCode += "private var skin : DisplayObject;\n");
			useValue && (declareCode += "private var value : Object;\n");
			(useSkin || useDisplayObject) && importList.push(DisplayObject);
			importList = ArrayUtils.createUniqueCopy(importList);
			var codeList : Array = [];
			for each (var clz:* in importList) {
				var clzName : String;
				if (clz is String) {
					clzName = clz;
				} else {
					var qName : QName = ReflectUtil.getQName(clz);
					if (qName.uri == null) {
						continue;
					}
					clzName = getQualifiedClassName(clz).replace("::", ".");
				}
				codeList.push(sprintf("import %s;", clzName));
			}
			codeList.sort();
			importCode = codeList.join("\n");
		}

		/**
		 * 准备一下
		 * 负责类名等相关的事宜
		 */
		private function prepare() : void {
			importList = [UIComponent];
			code = template;
			code = code.replace(/\${packageName}/g, detail.packageName);
			code = code.replace(/\${className}/g, detail.name);
			detail.container && (code = code.replace(/\${baseContainer}/g, importClass(detail.container.className)));
			declareCode = "";
		}

		private function generateBaseBody() : void {
			basebodyCode = "";
			var impl : DisplayObject = detail.containerImpl;
			var name : String = "super";
			// 基本属性
			for each (var property:PropertyConfig in detail.container.propertyList) {
				basebodyCode += getPropertyCode(impl, name, property);
			}
			// 样式
			for each (var style:StyleConfig in detail.container.styleList) {
				if (style.nopublish) {
					continue;
				}
				basebodyCode += getStyleCode(UIComponent(impl), name, style);
			}
		}

		/**
		 * 具体的生成背景部分
		 */
		private function generateBg() : void {
			backgroundCode = "";
			var len : int = detail.backgroundSkinList.length;
			var constructor : String;
			var code : String;
			for (var i : int = 0;i < len;i++) {
				constructor = "";
				code = "";
				var skin : SkinComponentAdapter = detail.backgroundSkinList[i];
				var clzName : String = skin.skin.clz ? importClass(skin.skin.clz) : skin.skin.name;
				saveBackgroundMeta(skin.skin.clz);
				var name : String;
				if (skin.name.indexOf("instance") == 0 || skin.name == "noname" ) {
					useSkin = true;
					name = "skin";
				} else {
					useDisplayObject = true;
					name = skin.name;
					declareCode += sprintf("protected var %s:DisplayObject;\n", skin.name);
				}
				// 构造
				useBgClass = true;
				// constructor = sprintf("clz=Class(getDefinitionByName(\"%s\"));\n%s = new clz();\n", clzName, name);
				importList.push(BitmapPool);
				constructor = sprintf("%s = BitmapPool.getBitmap(\"/image/ui/%s\");\n", name, clzName);
				// 布局
				code += sprintf("%s.x = %d;\n", name, skin.x);
				code += sprintf("%s.y = %d;\n", name, skin.y);
				code += sprintf("%s.width = %d;\n", name, skin.width);
				code += sprintf("%s.height = %d;\n", name, skin.height);
				// 添加
				code += sprintf("%s.name=\"%s\";\n", name, name);
				code += sprintf("addChild(%s);\n", name);
				// 合并
				backgroundCode += constructor;
				backgroundCode += code;
				backgroundCode += "\n";
			}
		}

		/**
		 * 保存背景样式的meta
		 */
		private function saveBackgroundMeta(clz : Class) : void {
			metaList.push({type:"background", clz:clz});
		}

		private function importClass(clz : *, fullName : Boolean = false) : String {
			clz = ReflectUtil.getClass(clz);
			var name : String = getQualifiedClassName(clz);
			if (fullName) {
				return name.replace("::", ".");
			}
			importList.push(clz);
			var index : int = name.indexOf("::");
			if (index >= 0) {
				return name.substring(name.indexOf("::") + 2);
			}
			return name;
		}

		/**
		 * 具体的生成主体
		 */
		private function generateBody() : void {
			bodyCode = "";
			var len : int = detail.uiList.length;
			var constructor : String;
			var code : String;
			for (var i : int = 0;i < len;i++) {
				constructor = "";
				code = "";
				var impl : DisplayObject = detail.uiList[i];
				var config : UiConfig = detail.configList[impl];
				if (config is ContainerConfig) {
					// 跳过窗体
					continue;
				}
				var clzName : String;
				if (config.className) {
					clzName = config.className.substring(config.className.lastIndexOf(".") + 1);
					importList.push(config.className);
				} else {
					clzName = importClass(impl);
				}
				var name : String = impl.name;
				var declare : Boolean = true;
				if (!name || name.indexOf("instance") == 0 || name == "noname") {
					// 不需要导出的说
					name = "noname" + (implCnt++);
					declare = false;
					// 构造
					constructor = sprintf("var %s:%s = new %s();\n", name, clzName, clzName);
				} else {
					// 构造
					constructor = sprintf("%s = new %s();\n", name, clzName);
				}
				var defaultComponent : UIComponent = ObjectPool.allocate(ReflectUtil.getClass(impl));
				// 基本属性
				for each (var property:PropertyConfig in config.propertyList) {
					if (property.key == "x") {
						code += sprintf("%s.x = %s;\n", name, impl.x);
					} else if (property.key == "y") {
						code += sprintf("%s.y = %s;\n", name, impl.y);
					} else if (!property.nopublish) {
						if (defaultComponent[property.key] == impl[property.key]) {
							// 如果和默认值一样就导出一个简单的注释
							code += getCommitCode(getPropertyCode(impl, name, property));
						} else {
							code += getPropertyCode(impl, name, property);
						}
					}
				}
				// 样式
				for each (var style:StyleConfig in config.styleList) {
					if (defaultComponent.getStyle(style.key) == UIComponent(impl).getStyle(style.key)) {
						code += getCommitCode(getStyleCode(UIComponent(impl), name, style));
					} else {
						code += getStyleCode(UIComponent(impl), name, style);
					}
				}
				code += sprintf("addChild(%s);\n", name);
				code += sprintf("children.push(%s);\n", name);

				// 合并
				bodyCode += constructor;
				bodyCode += code;
				bodyCode += "\n";
				if (declare) {
					// 声明部分
					declareCode += sprintf("protected var %s : %s;\n", name, clzName);
				}
			}
		}

		/**
		 * 保存代码到文件
		 */
		private function saveCode() : void {
			if (noAlert) {
				var stream : FileStream = new FileStream();
				stream.open(File.applicationDirectory.resolvePath(detail.projectPath + "/" + detail.name + ".as"), FileMode.WRITE);
				stream.writeUTFBytes(code);
				stream.close();
				Log.info("导出完毕 " + detail.fullPath);
				dispatch(new GUIEditorEvent(GUIEditorEvent.PUBLISH_AS_COMPLETE));
			} else {
				var file : File = new File();
				file.addEventListener(Event.COMPLETE, function() : void {
					Log.alert("导出完毕");
					dispatch(new GUIEditorEvent(GUIEditorEvent.PUBLISH_AS_COMPLETE));
				});
				file.save(code, detail.name + ".as");
			}
		}

		/**
		 * 合并代码片段
		 */
		private function merge() : void {
			code = replaceCode(code, "${meta}", metaCode);
			code = replaceCode(code, "${declare}", declareCode);
			if (useBgClass) {
				code = replaceCode(code, "${import}", importCode);
				code = replaceCode(code, "${background}", "var clz:Class;\n" + backgroundCode);
			} else {
				code = replaceCode(code, "${import}", importCode);
				code = replaceCode(code, "${background}", backgroundCode);
			}
			code = replaceCode(code, "${basebody}", basebodyCode);
			code = replaceCode(code, "${body}", bodyCode);
		}

		/**
		 * 生成一个属性的代码
		 */
		private function getPropertyCode(impl : DisplayObject, name : String, property : PropertyConfig) : String {
			if (property.nopublish) {
				// 不发布的代码
				return "";
			}
			var code : String = "";
			var value : String;
			if (property.format is BooleanFormat) {
				value = impl[property.key] ? "true" : "false";
			} else if (property.format is NumericFormat) {
				value = impl[property.key];
			} else if (property.format is StringFormat) {
				if (impl[property.key] == "null" || impl[property.key] == null) {
					// Pass
					return "";
				} else {
					value = sprintf("\"%s\"", impl[property.key]);
				}
			}
			code += sprintf("%s.%s = %s;\n", name, property.key, value);
			return code;
		}

		/**
		 * 生成一个样式的代码
		 */
		private function getStyleCode(impl : UIComponent, name : String, style : StyleConfig) : String {
			var code : String = "";
			var styleValue : * = UIComponent(impl).getStyle(style.key);
			if (!styleValue) {
				// 样式没有设置值
				return code;
			}
			if (style.format is TFFormat) {
				useValue = true;
				if (styleValue is String) {
					code += sprintf("value = \"%s\";\n", styleValue);
				} else if (styleValue is Class) {
					code += sprintf("value = \"%s\";\n", importClass(styleValue));
				} else if (styleValue is ConstTextFormat) {
					code += sprintf("value = new %s();\n", importClass(styleValue));
				} else {
					// 生成具体的实例
					code += sprintf("value = new %s();\n", importClass(styleValue));
					// 暂时只支持textFormat
					for each (var key:String in ["align", "color", "font", "size", "bold"]) {
						if (!styleValue[key]) {
							continue;
						}
						if (styleValue[key] is String) {
							code += sprintf("value.%s = \"%s\";\n", key, styleValue[key]);
						} else {
							code += sprintf("value.%s = %s;\n", key, styleValue[key]);
						}
					}
				}
				code += sprintf("%s.setStyle(\"%s\",value);\n", name, style.key);
			} else if (style.format is FilterFormat) {
				code += sprintf("%s.setStyle(\"%s\",\"%s\");\n", name, style.key, importClass(styleValue, true));
			} else if (style.format is StyleFormat) {
				code += sprintf("%s.setStyle(\"%s\",new %s);\n", name, style.key, importClass(styleValue));
			} else if (style.format is SkinFormat) {
				if (styleValue is String) {
					code += sprintf("%s.setStyle(\"%s\",\"%s\");\n", name, style.key, styleValue);
				} else {
					code += sprintf("%s.setStyle(\"%s\",\"%s\");\n", name, style.key, importClass(styleValue, true));
				}
			} else if (style.format is StringFormat) {
				code += sprintf("%s.setStyle(\"%s\",\"%s\");\n", name, style.key, style.format.transValueToString(styleValue));
			} else {
				code += sprintf("%s.setStyle(\"%s\",%s);\n", name, style.key, style.format.transValueToString(styleValue));
			}
			return code;
		}

		/**
		 * 保证尽可能正确的还原缩进的
		 */
		private static function replaceCode(code : String, p : String, repl : String) : String {
			var replList : Array = repl.split("\n");
			if (replList.length <= 1) {
				return code.replace(p, repl);
			}
			var codeList : Array = code.split("\n");
			for (var i : int = 0;i < codeList.length;i++) {
				var line : String = codeList[i];
				var index : int = line.indexOf(p);
				if (index < 0) {
					continue;
				}
				var space : String = line.substr(0, index);
				var suffix : String = line.substr(index + p.length);
				if (space.match(/^\s+/)) {
					// 需要处理缩进的说
					line = "";
					for each (var subLine:String in replList) {
						line += space + subLine + "\n";
					}
					line += suffix;
					codeList[i] = line;
				}
			}
			return codeList.join("\n");
		}

		/**
		 * 获取注释版本的代码
		 */
		private function getCommitCode(code : String) : String {
			return code.replace(/^(.)/g, "// $1");
		}
	}
}
